package com.zelic.znn.core;

/**
 * @since 17/07/2011
 * @author zelic
 * Filename: TrainingSet.java
 * Description: Collection of training example
 */
import java.util.*;
import java.io.*;

/**
 * Training set use to store all training example
 * @author zelic
 */
public class TrainingSet {

    private int numInput;
    private int numOutput;
    private ArrayList<TrainingExample> trainingData = new ArrayList<TrainingExample>();

    /**
     * Constructor for training set
     * @param numInput : number of inputs
     * @param numOutput : number of outputs
     */
    public TrainingSet(int numInput, int numOutput) {
        this.numInput = numInput;
        this.numOutput = numOutput;
    }

    /**
     * Get number of training examples
     * @return number of training examples
     */
    public int getNumTrainingData() {
        return trainingData.size();
    }

    /**
     * Get number of input elements
     * @return number of input elements
     */
    public int getNumInput() {
        return numInput;
    }

    /**
     * Get number of output elements
     * @return number of output elements
     */
    public int getNumOutput() {
        return numOutput;
    }
    
    /**
     * Get training data of current training set
     * return: training data
     */
    public List<TrainingExample> getTrainingExamples(){
        return trainingData;
    }

    /**
     * Add training example
     * @param trainingExample 
     */
    public void addTrainingExample(TrainingExample trainingExample) {
        trainingData.add(trainingExample);
    }

    /**
     * Add training example with input and output 
     * @param input
     * @param output 
     */
    public void addTrainingExample(double[] input, double[] output) {
        TrainingExample trainingExample = new TrainingExample(input.length, output.length, input, output);
        trainingData.add(trainingExample);
    }

    /**
     * Get training example at position x
     * @param x
     * @return 
     */
    public TrainingExample getTrainingExample(int x) {
        return trainingData.get(x);
    }

    /**
     * Import training examples from file
     * Structure of data file:
     * 1:   [int: number of inputs] [int:number of outputs] [int:number of examples]
     * 2-n: [double: value of inputs] [double: value of outputs]
     * @param filename
     * @return
     * @throws IOException 
     */
    public static TrainingSet importTrainingExamplesFromFile(String filename) throws IOException {
        DataInputStream inputStream = null;
        TrainingSet result = null;
        int numInput = 0;
        int numOutput = 0;
        int numExample = 0;
        try {
            inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
            numInput = inputStream.readInt();
            numOutput = inputStream.readInt();
            numExample = inputStream.readInt();
            result = new TrainingSet(numInput, numOutput);

            double[] input = new double[numInput];
            double[] output = new double[numOutput];

            for (int e = 0; e < numExample; e++) {
                for (int i = 0; i < numInput; i++) {
                    input[i] = inputStream.readDouble();
                }
                for (int i = 0; i < numOutput; i++) {
                    output[i] = inputStream.readDouble();
                }
                result.addTrainingExample(input, output);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return result;
    }

    /**
     * Import training examples from file with integer data
     * Structure of data file:
     * 1:   [int: number of inputs] [int:number of outputs] [int:number of examples]
     * 2-n: [double: value of inputs] [double: value of outputs]
     * @param filename
     * @return
     * @throws IOException 
     */
    public static TrainingSet importIntTrainingExamplesFromFile(String filename) throws IOException {
        DataInputStream inputStream = null;
        TrainingSet result = null;
        int numInput = 0;
        int numOutput = 0;
        int numExample = 0;
        try {
            inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
            numInput = inputStream.readInt();
            numOutput = inputStream.readInt();
            numExample = inputStream.readInt();
            result = new TrainingSet(numInput, numOutput);

            double[] input = new double[numInput];
            double[] output = new double[numOutput];

            for (int e = 0; e < numExample; e++) {
                for (int i = 0; i < numInput; i++) {
                    input[i] = (double) inputStream.readInt();
                }
                for (int i = 0; i < numOutput; i++) {
                    output[i] = (double) inputStream.readInt();
                }
                result.addTrainingExample(input, output);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return result;
    }
    
    /**
     * Add all training example from another training set
     * @param trainingSet : training set contain training data to import from
     */
    public void importTrainingExampleFromTrainingSet(TrainingSet trainingSet){
        trainingData.addAll(trainingSet.getTrainingExamples());
    }
}
